package com.ruoyi.system.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.domain.SysFile;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.utils.SecurityUtils;
import com.ruoyi.common.log.annotation.Log;
import com.ruoyi.common.log.enums.BusinessType;
import com.ruoyi.security.annotation.PreAuthorize;
import com.ruoyi.file.controller.SysFileController;
import com.ruoyi.system.domain.SysFaceLog;
import com.ruoyi.system.domain.SysSignIn;
import com.ruoyi.system.domain.SysSigninWorksite;
import com.ruoyi.system.domain.vo.*;
import com.ruoyi.system.service.ISysFaceLogService;
import com.ruoyi.system.service.ISysSignInService;
import com.ruoyi.system.service.ISysSigninWorksiteService;
import com.ruoyi.system.service.ISysUserService;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 用户签到Controller
 *
 * @author WJH
 * @date 2021-11-29
 */
@RestController
@RequestMapping("/system/SysSignIn")
public class SysSignInController extends com.ruoyi.common.core.web.controller.BaseController {
    @Autowired
    private ISysSignInService sysSignInService;
//    @Autowired
//    private RemoteFileService remoteFileService;
    @Autowired
    private SysFileController sysFileController;
    @Autowired
    private ISysFaceLogService sysFaceLogService;
    @Autowired
    private ISysSigninWorksiteService signinWorksiteService;
    @Autowired
    private ISysUserService userService;

    /**
     * 人脸识别成功的分数值
     */
    private static final String COMPARE_SCORE = "80";

    /**
     * 上班时间
     */
    private static final Integer START_TIME_H = 9;
    private static final Integer START_TIME_M = 0;
    private static final Integer START_TIME_S = 0;

    /**
     * 下班时间
     */
    private static final Integer END_TIME_H = 17;
    private static final Integer END_TIME_M = 30;
    private static final Integer END_TIME_S = 0;

    /**
     * 查看签到记录
     */
    @PreAuthorize
    @GetMapping("/list")
    @ApiOperation("查看签到记录")
    public com.ruoyi.common.core.web.page.TableDataInfo list(@RequestParam(name = "startTime", required = false) Long startTime, @RequestParam(name = "endTime", required = false) Long endTime,
                                                             @RequestParam(name = "userName", required = false) String userName,
                                                             @RequestParam(name = "deptId", required = false) Long deptId) throws ParseException {



        startPage();

        List<SysSignIn> list = sysSignInService.list(getListQueryWrapper(startTime,endTime,userName,deptId));

        com.ruoyi.common.core.web.page.TableDataInfo dataTable = getDataTable(list);
        dataTable.setData(resolveList(list));
        return dataTable;
    }

    private  List<SignInListVo>  resolveList(List<SysSignIn> list) {
        Set<Long> signIds = new HashSet<>();
        list.forEach(item-> signIds.add(item.getSignInId()));
        //构造签到记录与工作现场签到记录的一对多关系的Map



        HashMap<Long, List<SysSigninWorksite>> signInIdWorksiteMap = new HashMap<>();
        if(signIds.size()>0){
            List<SysSigninWorksite> worksites = signinWorksiteService.list(new QueryWrapper<SysSigninWorksite>().in(SysSigninWorksite.SIGN_IN_ID,signIds));
            if (worksites != null) {
                for (SysSignIn sysSignIn : list) {
                    List<SysSigninWorksite> values = new ArrayList<>();
                    for (SysSigninWorksite worksite : worksites) {
                        if (worksite.getSignInId() != null &&
                                worksite.getSignInId().equals(sysSignIn.getSignInId())) {
                            values.add(worksite);
                        }
                    }
                    if (values.size() > 0) {
                        signInIdWorksiteMap.put(sysSignIn.getSignInId(), values);
                    }
                }
            }
        }

        //构造前端展示的数据
        SimpleDateFormat fmt = new SimpleDateFormat("yyyy.MM.dd HH:mm");
        List<SignInListVo> vos = new ArrayList<>();
        if (list != null && list.size() > 0) {
            for (SysSignIn sysSignIn : list) {
                SignInListVo vo = new SignInListVo();
                SysSignInVo inVo = new SysSignInVo();
                BeanUtils.copyProperties(sysSignIn, inVo);

                String workOvertimeSituation = "";  //加班情况
                String lateSituation = "";          //迟到情况
                String leaveEarlySituation = "";    //早退情况
                String missCardSituation = "";      //缺卡情况
                Date workDate;
                Long a = sysSignIn.getStartWorkTime();
                Long b = sysSignIn.getEndWorkTime();
                if (a != null) {
                    workDate = new Date(a);
                } else {
                    workDate = new Date(b);
                }
                //设置上下班的时间
                GregorianCalendar gc3 = new GregorianCalendar();
                gc3.setTime(workDate);
                gc3.set(Calendar.HOUR_OF_DAY, START_TIME_H);
                gc3.set(Calendar.MINUTE, START_TIME_M);
                gc3.set(Calendar.SECOND, START_TIME_S);
                long startms = gc3.getTimeInMillis();

                GregorianCalendar gc4 = new GregorianCalendar();
                gc4.setTime(workDate);
                gc4.set(Calendar.HOUR_OF_DAY, END_TIME_H);
                gc4.set(Calendar.MINUTE, END_TIME_M);
                gc4.set(Calendar.SECOND, END_TIME_S);
                long endms = gc4.getTimeInMillis();

                //计算签到数据
                if (a != null) {
                    if (a > startms) {
                        lateSituation = "迟到" + String.format("%.1f", ((a - startms) * 1.0) / (1000 * 60) ) +"分钟";
                    } else {
                        lateSituation = "未迟到";
                    }
                } else {
                    missCardSituation = "上班缺卡";
                    lateSituation = "暂无";
                }
                if (b != null) {
                    if (b > endms || b == endms) {
                        if ((b - endms) > (1000 * 60 * 10)) {
                            //超过10分钟就算加班
                            workOvertimeSituation = "加班" + String.format("%.1f", ((b - endms) * 1.0) / (1000 * 60 * 60) ) + "小时";
                        } else {
                            workOvertimeSituation = "未加班";
                        }
                    } else {
                        leaveEarlySituation = "早退" + String.format("%.1f", ( (endms - b) * 1.0) / (1000 * 60) ) + "分钟";
                    }
                } else {
                    missCardSituation += "下班缺卡";
                    workOvertimeSituation = "暂无";
                    leaveEarlySituation = "暂无";
                }
                if (a != null && b != null) {
                    missCardSituation = "未缺卡";
                }
                inVo.setWorkOvertimeSituation(workOvertimeSituation);
                inVo.setLateSituation(lateSituation);
                inVo.setLeaveEarlySituation(leaveEarlySituation);
                inVo.setMissCardSituation(missCardSituation);
                vo.setSysSignIn(inVo);

                List<SysSigninWorksite> results = signInIdWorksiteMap.get(sysSignIn.getSignInId());
                List<SignInHistoryVo> list1 = new ArrayList<>();
                //添加上班签到信息
                if (sysSignIn.getStartWorkTime() != null) {
                    SignInHistoryVo sign_s = new SignInHistoryVo();
                    sign_s.setTime(fmt.format(new Date(sysSignIn.getStartWorkTime())));
                    sign_s.setLocation(sysSignIn.getStartWorkLocation());
                    sign_s.setType("上班签到");
                    sign_s.setLongitude(sysSignIn.getSLongitude());
                    sign_s.setLatitude(sysSignIn.getSLatitude());
                    list1.add(sign_s);
                }
                //添加工作现场签到信息
                if (results != null && results.size() > 0) {
                    for (SysSigninWorksite result : results) {
                        SignInHistoryVo sign = new SignInHistoryVo();
                        BeanUtils.copyProperties(result, sign);
                        sign.setTime(fmt.format(new Date(result.getWorkSiteTime())));
                        sign.setLocation(result.getWorkSiteLocation());
                        sign.setType("工作现场签到");
                        list1.add(sign);
                    }
                }
                //添加下班签到信息
                if (sysSignIn.getEndWorkTime() != null) {
                    SignInHistoryVo sign_e = new SignInHistoryVo();
                    sign_e.setTime(fmt.format(new Date(sysSignIn.getEndWorkTime())));
                    sign_e.setLocation(sysSignIn.getEndWorkLocation());
                    sign_e.setType("下班签到");
                    sign_e.setLongitude(sysSignIn.getELongitude());
                    sign_e.setLatitude(sysSignIn.getELatitude());
                    list1.add(sign_e);
                }
                vo.setWorkSites(list1);
                vos.add(vo);
            }
        }
        return vos;
    }

    private  QueryWrapper<SysSignIn> getListQueryWrapper(Long startTime, Long endTime, String userName, Long deptId) {
        QueryWrapper<SysSignIn> wrapper = new QueryWrapper<>();
        if (userName != null) {
            wrapper.like(SysSignIn.USER_NAME, userName);
        }
        if (deptId != null) {
            List<SysUser> users = userService.list(new QueryWrapper<SysUser>().eq(SysUser.DEPT_ID, deptId));
            HashSet<Long> userIds = new HashSet<>();
            if (users != null && users.size() > 0) {
                users.forEach(item -> userIds.add(item.getUserId()));
            }
            wrapper.in(SysSignIn.USER_ID, userIds);
        }
        wrapper.orderByDesc(SysSignIn.SIGN_IN_ID);

        if(startTime!=null){
            wrapper.gt(SysSignIn.START_WORK_TIME, startTime);

        }
        if(endTime!=null){
            wrapper.lt(SysSignIn.START_WORK_TIME,endTime);

        }
        return wrapper;
    }

    /**
     * 导出用户签到数据
     */
    @PreAuthorize
    @Log(title = "用户签到", businessType = BusinessType.EXPORT)
    @GetMapping(value="/export", produces = "application/octet-stream")
    @ApiOperation("导出用户签到数据")
    public void export(HttpServletResponse response,
                       @RequestParam(name = "startTime", required = false) Long startTime, @RequestParam(name = "endTime", required = false) Long endTime,
                       @RequestParam(name = "userName", required = false) String userName,
                       @RequestParam(name = "deptId", required = false) Long deptId) throws IOException, ParseException {
        com.ruoyi.common.core.utils.poi.ExcelUtil<SysSignIn> util = new com.ruoyi.common.core.utils.poi.ExcelUtil<>(SysSignIn.class);
        List<SysSignIn> list = sysSignInService.list(getListQueryWrapper(startTime,endTime,userName,deptId));

        util.exportExcel(response, list, "用户签到数据");

    }

    @PreAuthorize
    @ApiOperation("保存人脸识别结果")
    @PostMapping("/saveFaceResult")
    public com.ruoyi.common.core.web.domain.AjaxResult saveFaceResult(SaveFaceResultVo vo) {
        //保存人脸信息文件
        if (vo.getFaceFile().isEmpty())
            return com.ruoyi.common.core.web.domain.AjaxResult.error("人脸信息为空，请重新扫脸！");
        R<SysFile> faceFile = sysFileController.upload(vo.getFaceFile(), "faceFile");
        if (faceFile.getCode() == R.FAIL)
            throw new com.ruoyi.common.core.exception.ServiceException(faceFile.getMsg());
        String faceUrl = faceFile.getData().getUrl();
        //保存人脸识别结果
        SysFaceLog faceLog = new SysFaceLog();
        faceLog.setFaceUrl(faceUrl);
        faceLog.setCompareScore(vo.getCompareScore());
        sysFaceLogService.save(faceLog);
        return com.ruoyi.common.core.web.domain.AjaxResult.success("签到成功！", faceLog.getSysFaceId());
    }
    @PreAuthorize
    @ApiOperation("保存人脸识别结果")
    @PostMapping("/saveFaceResultNew")
    public com.ruoyi.common.core.web.domain.AjaxResult saveFaceResultNew(@RequestBody SysFaceLog faceLog) {

        sysFaceLogService.save(faceLog);
        return com.ruoyi.common.core.web.domain.AjaxResult.success("签到成功！", faceLog.getSysFaceId());
    }
    /**
     * 用户签到
     */
    @PreAuthorize
    @Log(title = "用户签到", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ApiOperation("用户签到")
    public com.ruoyi.common.core.web.domain.AjaxResult add(@RequestBody SysSignInAddVo vo) {
        //保存签到记录
        SysSignIn sysSignIn = new SysSignIn();
        BeanUtils.copyProperties(vo, sysSignIn);
        Long userId = SecurityUtils.getUserId();
        sysSignIn.setUserId(userId);
        sysSignIn.setUserName(SecurityUtils.getUsername());
        sysSignIn.setSysFaceId(vo.getSysFaceId());
        //获取当天凌晨0时0分0秒的时间
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        long time = calendar.getTimeInMillis();
        //记录当天签到记录
        switch (vo.getFlag()) {
            case 1: //上班打卡
                SysSignIn signIn = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, userId)
                        .gt(SysSignIn.START_WORK_TIME, time).lt(SysSignIn.START_WORK_TIME, System.currentTimeMillis()), false);
                if (signIn != null) {
                    return com.ruoyi.common.core.web.domain.AjaxResult.success("你已经完成上班打卡了，无需再打卡", "false");
                }
                sysSignIn.setStartWorkLocation(vo.getAutoLocation());
                sysSignIn.setStartWorkTime(System.currentTimeMillis());
                sysSignIn.setSLatitude(vo.getLatitude());
                sysSignIn.setSLongitude(vo.getLongitude());
                sysSignInService.save(sysSignIn);
                break;
            case 2: //下班打卡
                SysSignIn signIn2 = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, userId)
                        .gt(SysSignIn.END_WORK_TIME, time).lt(SysSignIn.END_WORK_TIME, System.currentTimeMillis()), false);
                if (signIn2 != null) {
                    return com.ruoyi.common.core.web.domain.AjaxResult.success("你已经完成下班打卡了，无需再打卡", "false");
                }
                SysSignIn signIn1 = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, userId)
                        .gt(SysSignIn.START_WORK_TIME, time).lt(SysSignIn.START_WORK_TIME, System.currentTimeMillis()), false);
                if (signIn1 != null) {
                    signIn1.setEndWorkLocation(vo.getAutoLocation());
                    signIn1.setEndWorkTime(System.currentTimeMillis());
                    signIn1.setELongitude(vo.getLongitude());
                    signIn1.setELatitude(vo.getLatitude());
                    sysSignInService.updateById(signIn1);
                } else {
                    sysSignIn.setEndWorkLocation(vo.getAutoLocation());
                    sysSignIn.setEndWorkTime(System.currentTimeMillis());
                    sysSignIn.setELongitude(vo.getLongitude());
                    sysSignIn.setELatitude(vo.getLatitude());
                    sysSignInService.save(sysSignIn);
                }
                break;
            case 3: //工作现场打卡
                SysSignIn signIn3 = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, userId)
                        .gt(SysSignIn.START_WORK_TIME, time).lt(SysSignIn.START_WORK_TIME, System.currentTimeMillis()), false);
                SysSignIn signIn4 = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, userId)
                        .gt(SysSignIn.END_WORK_TIME, time).lt(SysSignIn.END_WORK_TIME, System.currentTimeMillis()), false);
                SysSigninWorksite worksite = new SysSigninWorksite();
                if (signIn3 != null) {
                    worksite.setSignInId(signIn3.getSignInId());
                } else if (signIn4 != null) {
                    worksite.setSignInId(signIn4.getSignInId());
                } else {
                    worksite.setSignInId(null);
                }
                BeanUtils.copyProperties(vo, worksite);
                worksite.setUserId(userId);
                worksite.setUserName(SecurityUtils.getUsername());
                worksite.setWorkSiteLocation(vo.getAutoLocation());
                worksite.setWorkSiteTime(System.currentTimeMillis());
                signinWorksiteService.save(worksite);
                break;
        }
        return com.ruoyi.common.core.web.domain.AjaxResult.success("打卡成功！", "true");
    }

    @PreAuthorize
    @ApiOperation("查看签到记录")
    @GetMapping("/getSignInDetailByDate")
    public com.ruoyi.common.core.web.domain.AjaxResult getSignInDetailByDate(@RequestParam(value = "date", required = false) String date) throws ParseException {
        HistorySignInDetailVo result = new HistorySignInDetailVo();
        Date formatDate = new Date();
        if (date != null) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
            formatDate = format.parse(date);
        }
        //设置时间区间为指定日期的00:00:00-23:59:59
        GregorianCalendar gc1 = new GregorianCalendar();
        gc1.setTime(formatDate);
        gc1.set(Calendar.HOUR_OF_DAY, 0);
        gc1.set(Calendar.MINUTE, 0);
        gc1.set(Calendar.SECOND, 0);
        long startTime = gc1.getTimeInMillis();

        GregorianCalendar gc2 = new GregorianCalendar();
        gc2.setTime(formatDate);
        gc2.set(Calendar.HOUR_OF_DAY, 23);
        gc2.set(Calendar.MINUTE, 59);
        gc2.set(Calendar.SECOND, 59);
        long endTime = gc2.getTimeInMillis();

        //设置上下班的时间
        GregorianCalendar gc3 = new GregorianCalendar();
        gc3.setTime(formatDate);
        gc3.set(Calendar.HOUR_OF_DAY, START_TIME_H);
        gc3.set(Calendar.MINUTE, START_TIME_M);
        gc3.set(Calendar.SECOND, START_TIME_S);
        long startms = gc3.getTimeInMillis();

        GregorianCalendar gc4 = new GregorianCalendar();
        gc4.setTime(formatDate);
        gc4.set(Calendar.HOUR_OF_DAY, END_TIME_H);
        gc4.set(Calendar.MINUTE, END_TIME_M);
        gc4.set(Calendar.SECOND, END_TIME_S);
        long endms = gc4.getTimeInMillis();

        //开始构造签到详情的数据
        String startWorkTime = "";                         //上班签到时间
        String endWorkTime = "";                           //下班签到时间
        String workTime = "";                              //工作时长
        String workOvertimeSituation = "";                 //加班情况
        String lateSituation = "";                         //迟到情况
        String leaveEarlySituation = "";                   //早退情况
        String missCardSituation = "";                     //缺卡情况
        List<SignInHistoryVo> history = new ArrayList<>(); //当天签到记录
        Long a = null;
        Long b = null;

        SysSignIn startSignIn = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, SecurityUtils.getUserId())
                .gt(SysSignIn.START_WORK_TIME, startTime).lt(SysSignIn.START_WORK_TIME, endTime), false);
        SysSignIn endSignIn = sysSignInService.getOne(new QueryWrapper<SysSignIn>().eq(SysSignIn.USER_ID, SecurityUtils.getUserId())
                .gt(SysSignIn.END_WORK_TIME, startTime).lt(SysSignIn.END_WORK_TIME, endTime), false);
        List<SysSigninWorksite> signIns = signinWorksiteService.list(new QueryWrapper<SysSigninWorksite>()
                .eq(SysSigninWorksite.USER_ID, SecurityUtils.getUserId())
                .gt(SysSigninWorksite.WORK_SITE_TIME, startTime).lt(SysSigninWorksite.WORK_SITE_TIME, endTime));

        SimpleDateFormat fmt = new SimpleDateFormat("HH:mm");

        if (startSignIn != null) {
            SignInHistoryVo sign2 = new SignInHistoryVo();
            sign2.setLocation(startSignIn.getStartWorkLocation());
            sign2.setTime(fmt.format(new Date(startSignIn.getStartWorkTime())));
            history.add(sign2);

            a = startSignIn.getStartWorkTime();
            startWorkTime = fmt.format(new Date(a));
            if (a > startms) {
                lateSituation = "迟到" + String.format("%.1f", ((a - startms) * 1.0) / (1000 * 60) ) +"分钟";
            } else {
                lateSituation = "未迟到";
            }
        } else {
            missCardSituation = "上班缺卡";
            startWorkTime = "暂无";
            lateSituation = "暂无";
        }

        if (endSignIn != null) {
            SignInHistoryVo sign1 = new SignInHistoryVo();
            sign1.setLocation(endSignIn.getEndWorkLocation());
            sign1.setTime(fmt.format(new Date(endSignIn.getEndWorkTime())));
            history.add(sign1);

            b = endSignIn.getEndWorkTime();
            endWorkTime = fmt.format(new Date(b));
            if (b > endms || b == endms) {
                if ((b - endms) > (1000 * 60 * 10)) {
                    //超过10分钟就算加班
                    workOvertimeSituation = "加班" + String.format("%.1f", ((b - endms) * 1.0) / (1000 * 60 * 60) ) + "小时";
                } else {
                    workOvertimeSituation = "未加班";
                }
            } else {
                leaveEarlySituation = "早退" + String.format("%.1f", ( (endms - b) * 1.0) / (1000 * 60) ) + "分钟";
            }
        } else {
            missCardSituation += "下班缺卡";
            endWorkTime = "暂无";
            workOvertimeSituation = "暂无";
            leaveEarlySituation = "暂无";
        }

        if (startSignIn != null && endSignIn != null) {
            missCardSituation = "未缺卡";
        }

        if (a != null && b != null) {
            workTime = String.format("%.1f", ((b - a) * 1.0) / (1000 * 60 * 60) ) + "小时";
        }
        if (a != null && b == null) {
            workTime =  "未知";
        }
        if (a == null && b != null) {
            workTime =  "未知";
        }
        if (a == null && b == null) {
            workTime = "0小时";
        }

        if (signIns != null && signIns.size() > 0) {
            for (SysSigninWorksite signIn : signIns) {
                SignInHistoryVo vo = new SignInHistoryVo();
                vo.setLocation(signIn.getWorkSiteLocation());
                vo.setTime(fmt.format(new Date(signIn.getWorkSiteTime())));
                history.add(vo);
            }
        }
        history.sort(Comparator.comparing(SignInHistoryVo::getTime));

        result.setStartWorkTime(startWorkTime);
        result.setEndWorkTime(endWorkTime);
        result.setWorkTime(workTime);
        result.setWorkOvertimeSituation(workOvertimeSituation);
        result.setLateSituation(lateSituation);
        result.setLeaveEarlySituation(leaveEarlySituation);
        result.setMissCardSituation(missCardSituation);
        result.setHistory(history);

        return com.ruoyi.common.core.web.domain.AjaxResult.success(result);
    }

    /**
     * 获取指定时间到当前时间的签到记录
     *
     * @param startTime 指定时间
     * @return 满足条件的签到记录
     */
    @GetMapping("/getSignInListByStartTime")
    public R<List<SysSignIn>> getSignInListByStartTime(@RequestParam("startTime") Long startTime) {
        List<SysSignIn> list = sysSignInService.list(new QueryWrapper<SysSignIn>()
                .gt(SysSignIn.START_WORK_TIME, startTime)
                .or().gt(SysSignIn.END_WORK_TIME, startTime)
        );
        return R.ok(list);
    }
    @PostMapping("uploadFaceImage")
    public R<SysFile> upload(MultipartFile file) {
        try {
            // 上传并返回访问地址
            return sysFileController.upload(file, "");

        } catch (Exception e) {

            return R.fail(e.getMessage());
        }
    }

}
